package com.pic.others.service.impl;

import cn.hutool.core.util.StrUtil;
import com.pic.common.autoconfigure.mq.RabbitMqHelper;
import com.pic.common.constants.MqConstants;
import com.pic.common.enums.UserType;
import com.pic.common.utils.R;
import com.pic.common.utils.RandomUtils;
import com.pic.common.utils.StringUtils;
import com.pic.common.utils.UserContext;
import com.pic.others.config.minio.MinIOUtil;
import com.pic.others.domain.dto.user.LoginFormDTO;
import com.pic.others.domain.dto.user.LoginUserDTO;
import com.pic.others.domain.dto.user.UserDTO;
import com.pic.others.domain.dto.user.UserFormDto;
import com.pic.others.domain.po.User;
import com.pic.others.mapper.UserMapper;
import com.pic.others.mq.message.EmailMessage;
import com.pic.others.service.ICodeService;
import com.pic.others.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import static com.pic.common.constants.RedisConstants.jwt.LOGIN_TOKEN_KEY;
import static com.pic.others.constants.user.UserConstants.*;
import static com.pic.others.constants.user.UserErrorInfo.Msg.*;
import static com.pic.others.constants.user.UserSuccessInfo.Msg.*;


/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author koshi
 * @since 2023-11-24
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    private final ICodeService codeService;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenService jwtTokenService;
    private final StringRedisTemplate stringRedisTemplate;
    private final RabbitMqHelper mqHelper;
    private final MinIOUtil minIOUtil;

    @Value("${minio.bucket}")
    String bucket;

    @Value("${picture.save}")
    private String localte;


    @Override
    public R<String> saveUser(UserFormDto userFormDto) {
        //新增用户账号
        User user=new User();
        user.setEmail(userFormDto.getEmail());
        user.setPassword(userFormDto.getPassword());
        user.setType(UserType.USER.getValue());//设置为用户
        if( addUserByEmail(user,userFormDto.getCode())){
            return R.success(USER_SUCCESS_REGISTER);
        }
        return R.error(USER_ERROR_REGISTER);
    }


    /**
     * 方法：
     * @param user
     * @param code
     * @return
     */
    @Override
    public boolean addUserByEmail(User user, String code) {
        //1.验证码校验
        boolean flag=codeService.verifyCode(user.getEmail(),code,USER_VERIFY_CODE_KEY_REGISTER);
        if(!flag)return false;
        //2.判断邮箱是否存在
        Integer count =lambdaQuery().eq(User::getEmail,user.getEmail()).count();
        if(count>0){
            log.info(EMAIL_ALREADY_EXISTS);
            return false;
        }
        //3.加密密码
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        /*
        补充下解密配对
        !passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())
        如果是true则配对失败，
        是false则是成功，密码正确·
         */
        user.setIsvip(NOVIP);
        user.setName(RandomUtils.randomString(8));
        user.setType(UserType.USER.getValue());
        save(user);//保存用户信息
        return true;
    }

    @Transactional
    @Override
    public R<User> updateUser(@Valid UserDTO userDTO) {
        Long userId=UserContext.getUser();
        User user=getById(userId);
        user.setBirthday(userDTO.getBirthday());
        user.setName(userDTO.getName());
        user.setSex(userDTO.getSex());
        user.setSign(userDTO.getSign());
        boolean flag = updateById(user);
        if(flag){
            return R.success(user);
        }
        return R.error(USER_ERROR_UPDATE);
    }

    @Override
    public R<LoginUserDTO> queryUser(LoginFormDTO loginFormDTO) {
        log.info("loginFormDTO:{}",loginFormDTO);
        //1.判断登录方式
        Integer type=loginFormDTO.getType();
        User user=null;
        //2.用户和密码登录
       if(type==1){
           user=loginByPw(loginFormDTO);
       }
       //3.验证码登录
        if(type==2){
            user=loginByVerifyCode(loginFormDTO.getEmail(),loginFormDTO.getCode());
        }
        //4.错误登录
        if(user==null){
            log.error(ILLEGAL_LOGIN_TYPE);
            return R.error(ILLEGAL_LOGIN_TYPE);
        }

        // 用户登录成功后，生成 Token
        Long userId = user.getUserId(); // 你的 User 对象中应该有获取用户 ID 的方法
        String username = user.getName(); // 获取用户名
        String token = jwtTokenService.generateToken(userId, username);
        // 将 Token 存储到 Redis 中，这里使用登录用户的 ID 作为 Redis Key

        stringRedisTemplate.opsForHash().put(LOGIN_TOKEN_KEY,token,user.getUserId().toString());
        log.info("token解密是:{}",jwtTokenService.parseToken(token).toString());
        log.info("{}",jwtTokenService.parseToken(token).get("userId",Long.class));




//        //6.封装返回
        LoginUserDTO userDTO=new LoginUserDTO();
        userDTO.setUserId(user.getUserId());
        userDTO.setType(UserType.USER.getValue());
        userDTO.setToken(token);
        Long id = UserContext.getUser();
        log.info("我猜你有放线程池：{}",id);
        return R.success(userDTO);
    }


    @Override
    public R<String> sendCode(String email,Integer number) {
        log.info("number{}",number);
        //1
        if (number==null){
            return R.error("请求有误");
        }
        if(number==1){
            mqHelper.send(
                    MqConstants.Exchange.SMS_EXCHANGE,
                    MqConstants.Key.SMS_MESSAGE,
                    EmailMessage.of(email,USER_VERIFY_CODE_KEY_REGISTER)
            );
        }
//        codeService.sendVerifyCode(email,USER_VERIFY_CODE_KEY_REGISTER);

        else {
            mqHelper.send(
                    MqConstants.Exchange.SMS_EXCHANGE,
                    MqConstants.Key.SMS_MESSAGE,
                    EmailMessage.of(email,USER_VERIFY_CODE_KEY_LOGIN)
            );
        }


//            codeService.sendVerifyCode(email,USER_VERIFY_CODE_KEY_LOGIN);
        return R.success("发送成功，请尽快提交验证");
    }


    //通过验证码
    private User loginByVerifyCode(String email, String code) {
        //1.校验验证码
        log.info("email:{},code:{}",email,code);

//        boolean flag=codeService.verifyCode(user.getEmail(),code,USER_VERIFY_CODE_KEY_REGISTER);
        boolean flag = codeService.verifyCode(email, code,USER_VERIFY_CODE_KEY_LOGIN);
        log.info("flag:{}",flag);
        if(!flag)return null;
        //2.根据邮箱号进行查询
        User user=lambdaQuery().eq(User::getEmail,email).one();
        if(user==null){
            log.error(PHONE_NOT_EXISTS);
        }
        log.info("user:{}",user);
        return user;
    }

    private User loginByPw(LoginFormDTO loginFormDTO) {
        //1.数据校验
        String name=loginFormDTO.getName();
        String email=loginFormDTO.getEmail();
        if(StrUtil.isBlank(name)&&StrUtil.isBlank(email)){
//            throw new BadRequestException(INVALID_UN);
            log.info(INVALID_UN);
            return null;
        }
        //2.根据邮箱查询
        User user=lambdaQuery().eq(StrUtil.isNotBlank(email),User::getEmail,email)
                .one();
        if(user==null){
           return null;
        }
        //3.校验密码
        if(!passwordEncoder.matches(loginFormDTO.getPassword(),user.getPassword())){
            log.info("账户或密码错误");
            return null;
        }
        return user;

    }

    @Override
    public R<String> updateUserPassword(UserFormDto userFormDto, String checkPassword) {
        //先验证 验证码
        boolean flag = codeService.verifyCode(userFormDto.getEmail(), userFormDto.getCode(),USER_VERIFY_CODE_KEY_LOGIN);
        if(!flag){
            return R.error(EMAILVER_ERROR_NOT_EXISIS);
        }
        if(StringUtils.isNotBlank(userFormDto.getPassword())&& StringUtils.isNotBlank(checkPassword)){
            if(!userFormDto.getPassword().equals(checkPassword)){
                return R.error(PASSWORD_IS_DIFF);
            }

            lambdaUpdate().set(userFormDto.getPassword()!=null,User::getPassword,passwordEncoder.encode(userFormDto.getPassword()));
            return R.success(USER_SUCCESS_UPDATE);
        }
        return R.error(PASSWORD_IS_NULL);
    }

    @Override
    public R<User> updateUserImg(HttpServletRequest request, MultipartFile file) {
        if(file==null||file.getSize()==0){
            return R.error("上传为空");
        }
        Long userId = UserContext.getUser();
        User user = getById(userId);
        String prefix=String.valueOf(userId);
        String  locate = minIOUtil.uploadImgFile(bucket, prefix, file, null);
        log.info("上传图片到Minio中，图片路径是{}",locate);
        user.setImg(locate);
        updateById(user);
        return R.success(user);

    }

    @Override
    public R<User> getUserInfo() {
        Long userId = UserContext.getUser();
        if(userId==null){
            return R.error("请先登录");
        }
        User user = getById(userId);
        if(user==null){
            return R.error("此用户不存在");
        }
        return R.success(user);
    }
}
